home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / MCQUAY1 / FILEIO6.PAS next >
Pascal/Delphi Source File  |  1995-05-22  |  17KB  |  501 lines

  1. unit fileio6;
  2. {**************************************************************************
  3.    ADVANCED FILE IO FOR TURBO PASCAL VER 6.0
  4.    Copyright 1991 McQuay Technologies
  5.    r.quay
  6.    ver 6.1
  7.    Dec 17 1991
  8.    McQuay Technologies
  9.    2329 E.Cortez
  10.    Phoenix AZ, 85028
  11.    Compuserve ID
  12.  
  13.    These routines extend the File I/O capabilties of Turbo Pascal Version
  14.    6.0 and 7.0 .  They permit rapid random access file I/O on unstructured
  15.    or varied structure files.  They can be mixed freely with all
  16.    the standard pascal I/O procedures and functions, however,
  17.    these extensions do effect the behavior of Turbo's standard
  18.    I/O procedures and functions in very predicatble ways.
  19.    There in lies the power and flexibility of these routines.
  20.  
  21.    It is reccomended that only experienced programmers attempt to utilize
  22.    these routines.
  23.  
  24.    DOS Versions MS/PC DOS  2.x,3.x,4.x,5.x
  25.    Turbo Versions 6.0 and 7.0 Only !!!
  26.  
  27. **************************************************************************}
  28.  
  29. interface
  30.   uses dos;
  31.   Type
  32.         TFileStatus = (unassigned,Closed,Open,Unknown);
  33.         TFilePath = string[80];
  34.   function AbsoluteSeek( Var FileType; fileOffset:longint;
  35.                          var FilePos:longint):word;
  36.    function RelativeSeek( Var FileType; RelativeOffset:longint;
  37.                           var FilePos:longint):word;
  38.   procedure EOFSeek( Var FileType; var Offset:longint; Var Status:word);
  39.   function AbsoluteRead( Var FIleType; Var Buffer; BytesToRead: word;
  40.                          Var BytesRead:word):word;
  41.   function AbsoluteWrite( var FIleType; Var Variable; BytestoWrite:word;
  42.                           var BytesWritten:word):word;
  43.   function FileRecordLength(Var FileType):word;
  44.   function AbsoluteFilePos(Var FileType; Var Status:word):longint;
  45.     function TurboFileStatus(Var FileType):Tfilestatus;
  46.   function TurboFileMode(Var FileType):word;
  47.   function TurboFileHandle(Var FileType):integer;
  48.   procedure ForceUpdate(var FileType; var Status:word);
  49.   function FastBinaryCopy(var FileTypeSource; var FileTypeTarget):word;
  50.     function FIleCopy(Source,Target:TFilePath):word;
  51. implementation
  52.  
  53. {-------------------------------------------------------------------------}
  54. Function CF(Flags:word):Boolean;
  55. { Returns TRUE if Carry Flag is set  }
  56. Begin
  57.   if (Flags and $1) = 1 then
  58.     CF := True
  59.   Else
  60.     CF := False;
  61. End;
  62. {-------------------------------------------------------------------------}
  63. { These 3 proccedures provide direct random access to any file, independent
  64.   of the file's record size or type. (i.e. it works on TEXT filetypes!).
  65.  
  66.   ABSOLUTESEEK positions the file pointer OFFSET bytes from the beginning
  67.   of the file.  RELATIVESEEK positions the file pointer OFFSET bytes from the
  68.   current position of the file pointer.  EOFSEEK positions the file pointer
  69.   at the end of the file, and returns its position in bytes in OFFSET (This
  70.   of course limits you to a 2 gigabyte file size, too bad).
  71.  
  72.   These routines can be mixed freely with Turbo's IO procedures, however
  73.   they do have some rather predicatable and remarkable effects.
  74.   They are very useful for working with random access files not
  75.   created with Turbo Pascal. i.e. dBase II and III, BASIC, Lotus Etc.
  76.   Using thiese seek routines with an offset which is not
  77.   a multiple of a TP file's record length, effectively shifts where the
  78.   normal Turbo READ and WRITE routines will begin reading records.  For
  79.   example, a BASIC BSAVE file of the Text Screen could be considered a
  80.   Random Access file concisting of 25 ,160 byte records, EXCEPT, BASIC
  81.   puts seven bytes of code in front of the file.  A Turbo routine could
  82.   be written to open a file with a 160 byte record length, and use this
  83.   seek to skip those seven bytes, before it starts reading any records
  84.   with Turbo's normal READ and WRITE.  OH YES! Now you will begin to do
  85.   some of the creative and flexible File I/O not normally possible with
  86.   PASCAL, ah but read on!
  87.  
  88.   If the I/O operation was successful, then 0 will be returned.
  89.   If an error occurs, then the value returned will be the code for
  90.   DOS's Error Return Table.   Errors 5 - Access denied, and 6 - Invalid
  91.   Handle will be the most common.  If STATUS returns $25, then the
  92.   file specified has not yet been opened.
  93.  
  94.   CAUTION:  This routines will gladly let you seek beyond the current
  95.   end of file.
  96. }
  97.   function AbsoluteSeek( Var FileType; FileOffset:longint;
  98.                          var FilePos:longint):word;
  99.  
  100.   begin
  101.   asm
  102.     les di,FileType
  103.     mov AX,es:[di+2]
  104.     and AX,0D703H
  105.     cmp AX,0D701H
  106.     jb @3
  107.     mov AL,0;
  108.     mov BX,es:[di];
  109.     mov CX,word ptr FileOffset+2
  110.     mov DX,word ptr FileOffset
  111.     mov AH,42H
  112.     int 21h
  113.     les di,FilePos
  114.     jc @2
  115.     mov word ptr es:[di+2],DX
  116.     mov word ptr es:[di],AX
  117.     mov AX,0
  118.     jmp @2
  119.     @3:
  120.     mov AX,70h
  121.     @2:
  122.     mov @Result,AX
  123.     end;
  124.  
  125.  end;
  126. {-------------------------------------------------------------------------}
  127.    function RelativeSeek( Var FileType; RelativeOffset:longint;
  128.                           var FilePos:longint):word;
  129.      begin
  130.      asm
  131.        les di,FileType
  132.        mov AX,es:[di+2]
  133.        and AX,0D703H
  134.        cmp AX,0D701H
  135.        jb @3
  136.        mov AL,1;
  137.        mov BX,es:[di];
  138.        mov CX,word ptr RelativeOffset+2
  139.        mov DX,word ptr RelativeOffset
  140.        mov AH,42H
  141.        int 21h
  142.        les di,FilePos
  143.        jc @2
  144.        mov word ptr es:[di+2],DX
  145.        mov word ptr es:[di],AX
  146.        mov AX,0
  147.        jmp @2
  148.        @3:
  149.        mov AX,70h
  150.        @2:
  151.        mov @result,AX
  152.        end;
  153.     end;
  154. {-------------------------------------------------------------------------}
  155. Procedure EOFSeek( Var FileType; var Offset:longint; Var Status:word);
  156. var
  157.   FileFIB : FileRec absolute FileType;
  158.   Reg : Registers;
  159.   longoffset : record
  160.     loword,hiword : word;
  161.     end     absolute offset;
  162. Begin
  163.   if ((FileFIB.Mode and $D703)<$D701)  then
  164.     begin
  165.       Status := $25;
  166.       Exit;
  167.     End;
  168.   Reg.AL := 2;
  169.   Reg.BX := FileFIB.Handle;
  170.   Reg.CX := 0;
  171.   Reg.DX := 0;
  172.   Reg.AH := $42;
  173.   MsDos(Reg);
  174.   If CF(Reg.Flags) then
  175.     Status := Reg.AL
  176.   else
  177.     begin
  178.     LongOffset.hiword := reg.DX;
  179.     LongOffset.loword := reg.AX;
  180.     Status := 0;
  181.     end;
  182. End;
  183.  
  184. {-------------------------------------------------------------------------}
  185. function AbsoluteRead( Var FIleType; Var Buffer; BytesToRead: word;
  186.                         Var BytesRead:word):word;
  187. {  This procedure gives you the flexibility in the READ statement that
  188.    AbsoluteSeek gives for the SEEK Statement.  This procedure will read
  189.    from the file specified in FILETYPE, starting at the current file
  190.    pointer (which can be set by SEEK() AbsoluteSeek() or a READ()), the
  191.    number of bytes specified in BYTESTOREAD are place in the data
  192.    structure specified by VARIABLE.  The file pointer is moved forward
  193.    BYTESTOREAD bytes, regardless of the files record length.  The
  194.    number of bytes actually read is returned in BYTESREAD.  This will
  195.    happen if the file pointer is closer to the end of the file than
  196.    BYTESTOREAD.  The function  will return  the DOS errorcode found in
  197.    the AL register if the carry flag has been set. returns a 0 if no error
  198.    condition was found.  If BYTESTOREAD = 0 and the function returns 0
  199.    then the filepointer was at the end of the file. If this file handle
  200.    is redirected input, say from the keyboard, the requested number of
  201.    bytes is not always read (i.e. reading beyond the end of the file).
  202.    Errors 5 - Access denied, and 6 - Invalid Handle will be the most
  203.    common.  If STATUS returns hex ($)70, then the file specified has
  204.    not yet been opened with a Turbo assign and reset or rewrite Statement,
  205.    this is not a DOS file error.
  206.  
  207.    **** NOTE !!!  It is the programmers responsibility to insure that the
  208.    data structure specified, is large enough to receive the bytes specified.
  209.    if you request to read more bytes than there is room to do so, then this
  210.    routine will write over what ever data is contiguous to the data
  211.    structure passed.  This will get real messy so be careful!                                         }
  212.  
  213. var
  214.   FileFIB : FIleRec absolute FileType;
  215.   FileHandle:word;
  216. Begin
  217.   if ((FileFIB.Mode and $D703)<$D701) then
  218.     begin
  219.       AbsoluteRead := $70;
  220.       Exit;
  221.     End;
  222.   FileHandle := FileFIB.Handle;
  223.   asm
  224.     push ds
  225.     mov AL,0
  226.     mov BX,FileHandle
  227.     mov CX,BytesToRead
  228.     lds si,Buffer
  229.     mov dx,si
  230.     mov AH,3FH
  231.     int 21h
  232.     jnc @1
  233.     les DI,BytesRead
  234.     mov @result,AX
  235.     mov word ptr es:[di],0
  236.     jmp @2
  237.     @1:
  238.     mov @result,0
  239.     les DI,BytesRead
  240.     mov es:[di],AX
  241.     @2:
  242.     pop ds
  243.     end;
  244. End;
  245. {-------------------------------------------------------------------------}
  246.   function AbsoluteWrite( var FIleType; Var Variable; BytestoWrite:word;
  247.                           var BytesWritten:word):word;
  248.  
  249. {  This procedure gives you the flexibility in the WRITE statement that
  250.    AbsoluteSeek gives for the SEEK Statement.  This procedure will write
  251.    to the file specified in FILETYPE, starting at the current file
  252.    pointer (which can be set by SEEK() AbsoluteSeek() READ()) or WRITE(), the
  253.    number of bytes specified in BYTES from the data structure specified
  254.    by VARIABLE.  The file pointer is moved forward BYTES bytes,
  255.    regardless of the files record length.
  256.  
  257.    If the I/O operation was successful, then STATUS will return a 0.
  258.    If an error occurs, then Status will contain the code for
  259.    DOS's Error Return Table.   Errors 5 - Access denied, and 6 - Invalid
  260.    Handle will be the most common.  If STATUS returns $25, then the
  261.    file specified has not yet been opened.
  262.  
  263.    Bytes will always return the number of bytes actually written.  If this
  264.    does not match the number requested be written, then status will return
  265.    a $26, which most likely means the disk is full.
  266.  
  267.    **** NOTE !!!  It is the programmers responsibility to insure that the
  268.    data structure specified, is large enough to contain the bytes specified
  269.    for the write operation.  This will not cause any fatal errors, but could
  270.    end up dumping a lot of junk to the disk
  271.                                                   }
  272. var
  273.   FileFIB : FIleRec absolute FileType;
  274.   Reg : Registers;
  275.  
  276. Begin
  277.   if ((FileFIB.Mode and $D703)<$D701) then
  278.     begin
  279.       AbsoluteWrite := $25;
  280.       Exit;
  281.     End;
  282.   Reg.AL := 0;
  283.   Reg.BX := FileFIB.Handle;
  284.   Reg.CX := BytesToWrite;
  285.   Reg.DS := Seg(Variable);
  286.   Reg.DX := Ofs(Variable);
  287.   Reg.AH := $40;
  288.   MsDos(Reg);
  289.   If CF(Reg.FLAGS) then
  290.       AbsoluteWrite := Reg.AX
  291.     Else
  292.       begin
  293.       AbsoluteWrite := 0;
  294.       BytesWritten := Reg.AX
  295.       end;
  296. End;
  297. {-------------------------------------------------------------------------}
  298. Function AbsoluteFilePos(Var FileType; Var Status:word):longint;
  299.  
  300. {  This function returns the current absolute position of the file
  301.    pointer for the file specified in FileType.  The Turbo function
  302.    FilePos() returns the record position of the file, while this
  303.    function returns the actual number of bytes the pointer is offset
  304.    from the beginning of the file.                                      }
  305.  
  306. var
  307.   FileFIB : FileRec absolute FileType;
  308.   Reg : Registers;
  309.   Position: record
  310.      case byte of
  311.      1:(loword,hiword: word);
  312.      2:(FP:longint);
  313.      end;
  314. Begin
  315.   if ((FileFIB.Mode and $D703)<$D701) then
  316.     begin
  317.       Status := $25;
  318.       Exit;
  319.     End
  320.   else
  321.     Status := 0;
  322.   Reg.AL := 1;
  323.   Reg.BX := FileFIB.Handle;
  324.   Reg.CX := 0;
  325.   Reg.DX := 0;
  326.   Reg.AH := $42;
  327.   MsDos(Reg);
  328.   Position.loword := reg.AX;
  329.   Position.hiword := reg.DX;
  330.   AbsoluteFilePos := Position.FP;
  331. End;
  332. {-------------------------------------------------------------------------}
  333. function TurboFileStatus(Var FileType):Tfilestatus;
  334.  
  335. { This function returns the status of a Turbo File Type, essentially if
  336.   it open or closed.  }
  337. var
  338.   FileFIB : FileRec absolute FileType;
  339. begin
  340.   case lo(FileFIB.mode) of
  341.     $B0 : TurboFileStatus := Closed;
  342.     $B1,$B2,$B3 : TurboFileStatus := Open;
  343.      else TurboFileStatus := Unknown;
  344.   end;
  345. end;
  346.  
  347.  
  348. {-------------------------------------------------------------------------}
  349. Function FileRecordLength(Var FileType):word;
  350.  
  351. {  This is a simple function that returns what Turbo has set the record
  352.    length of the file specified in FileType.  A zero value is returned
  353.    if the file is closed.  If the file is a textfile the results of this
  354.    function are not the Record Length of the file but the size of the
  355.    text buffer Turbo is using. See Turbo Manual for more info (Ver 4.0
  356.    page 298).                                     }
  357.  
  358. Var
  359.   FIB:FileRec absolute FileType;
  360. Begin
  361.   FileRecordLength := FIB.recsize;
  362. End;
  363. {-------------------------------------------------------------------------}
  364. { The following routines are just a convienent way to access information
  365.   conatined in Turbo's file record structure . }
  366. function TurboFileMode(Var FileType):word;
  367. var
  368.   FileFIB : FileRec absolute FileType;
  369. begin
  370.   TurboFileMode := FileFIB.mode;
  371. end;
  372. {-------------------------------------------------------------------------}
  373. function TurboFileHandle(Var FileType):integer;
  374. var
  375.   FileFIB : FileRec absolute FileType;
  376. begin
  377.   TurboFIleHandle := FileFIB.Handle;
  378. end;
  379. {-------------------------------------------------------------------------}
  380. procedure ForceUpdate(var FileType;var status : word);
  381. var
  382.   FileFIB : FileRec absolute FileType;
  383.   Reg : Registers;
  384.   NewHandle : word;
  385. begin
  386.   if ((FileFIB.Mode and $D703)<$D701)  then
  387.     begin
  388.       Status := $25;
  389.       Exit;
  390.     End;
  391.   Reg.AL := 0;
  392.   Reg.BX := FileFIB.Handle;
  393.   Reg.AH := $45;
  394.   MsDos(Reg);
  395.   If CF(Reg.Flags) then
  396.     begin
  397.     Status := Reg.AL;
  398.     exit;
  399.     end;
  400.  
  401.   Reg.BX := Reg.AX;
  402.   Reg.AL := 0;
  403.   Reg.AH := $3E;
  404.   MsDos(Reg);
  405.   If CF(Reg.Flags) then
  406.     Status := Reg.AL
  407.   else
  408.     Status := 0
  409. End;
  410. {---------------------------------------}
  411.     function FastBinaryCopy(var FileTypeSource; var FileTypeTarget):word;
  412.       var
  413.         Buffer: pointer;
  414.         MoveSize:word;
  415.         ByteIn,BytesRead,junk:word;
  416.         Error : word;
  417.         Temp:longint;
  418.       begin
  419.       error := 0;
  420.       if MaxAvail < 256 then
  421.         error := $ff
  422.       else
  423.         begin
  424.         if MaxAvail < 9*512 then
  425.           MoveSize := MaxAVail
  426.         else
  427.           MoveSize := 9*512;
  428.         getmem(Buffer,MoveSize);
  429.         Temp := absoluteFilePos(FileTypeSource,error);
  430.         repeat
  431.           ByteIn := MoveSize;
  432.           error := absoluteRead(FileTypeSource,buffer^,ByteIn,BytesRead);
  433.           if BytesRead>0 then
  434.             error := absolutewrite(FileTypeTarget,buffer^,BytesRead,junk);
  435.           until (error<>0)or(BytesRead=0);
  436.         freemem(Buffer,MoveSize);
  437.         end;
  438.       AbsoluteSeek(FileTypeSource,Temp,Temp);
  439.       FastBinaryCopy := error;
  440.       end;
  441.  
  442.     {--------------------------------------------}
  443.         function FIleCopy(Source,Target:TFilePath):word;
  444.       var
  445.         SourceF,TargetF:File;
  446.         Error : word;
  447.         FT,FS:longint;
  448.         DriveID:byte;
  449.       {--------------------}
  450.       function ioOk:boolean;
  451.         begin
  452.         if error=0 then
  453.           begin
  454.           Error := ioresult;
  455.           if Error>0 then
  456.             ioOk := false
  457.           else
  458.             ioOk := true;
  459.           end;
  460.         end;
  461.       {--------------------}
  462.       begin
  463.       if Source=Target then
  464.         begin
  465.         FileCopy := 1;
  466.         exit;
  467.         end
  468.       else
  469.         error := 0;
  470.       assign(SourceF,Source);
  471.       reset(SourceF);
  472.  
  473.       if ioOk then
  474.         begin
  475.         FS := FileSize(SourceF);
  476.         if Target[2]=':' then
  477.           DriveID := byte(Target[1]) and $f
  478.         else
  479.           DriveID := 0;
  480.         if Diskfree(DriveID)<FS then
  481.           Error := 1
  482.         else
  483.           begin
  484.           GetFTime(SourceF,FT);
  485.           assign(TargetF,Target);
  486.           rewrite(TargetF);
  487.           if ioOk then
  488.             begin
  489.             error := FastBinaryCopy(SourceF,TargetF);
  490.             SetFTime(TargetF,FT);
  491.             close(TargetF);
  492.             end;
  493.           Close(SourceF);
  494.           end;
  495.         end;
  496.       FileCopy := error;
  497.       end;
  498.  
  499.  
  500. end.
  501.